#!/bin/bash

# Git Changes Collector - Bash Version
# Collects changed files from Git repositories and saves them to a specified folder

# Show help message
function show_help {
    echo "Git Changes Collector"
    echo "===================="
    echo "Usage: $0 [OPTIONS] [REPOSITORIES...]"
    echo ""
    echo "Options:"
    echo "  -o, --output-folder NAME  Specify output folder name (default: collected_changes)"
    echo "  -h, --help                Show this help message"
    echo ""
    echo "Examples:"
    echo "  $0"
    echo "  $0 -o MyChanges"
    echo "  $0 /path/to/repo1 /path/to/repo2"
    echo ""
}

# Test if a directory is a Git repository
function test_git_repository {
    local repo_path="$1"
    [[ -d "$repo_path/.git" ]] && [[ -n "$(ls -A "$repo_path/.git" 2>/dev/null)" ]]
}

# Get all changed files (unstaged, staged, untracked)
function get_changed_files {
    local repo_path="$1"
    {
        git -C "$repo_path" diff --name-only 2>/dev/null
        git -C "$repo_path" diff --name-only --cached 2>/dev/null
        git -C "$repo_path" ls-files --others --exclude-standard 2>/dev/null
    } | sort -u
}

# Get all deleted files (unstaged, staged, tracked)
function get_deleted_files {
    local repo_path="$1"
    {
        git -C "$repo_path" diff --name-only --diff-filter=D 2>/dev/null
        git -C "$repo_path" diff --name-only --cached --diff-filter=D 2>/dev/null
        git -C "$repo_path" ls-files --deleted 2>/dev/null
    } | while IFS= read -r file; do
        # Clean file name
        clean_file=$(echo "$file" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
        [[ -z "$clean_file" ]] && continue
        # Remove non-printable characters
        clean_file=$(echo "$clean_file" | tr -cd '[:print:]')
        [[ -z "$clean_file" ]] && continue
        echo "$clean_file"
    done | sort -u
}

# Copy a file while maintaining directory structure
function copy_file_with_structure {
    local source_file="$1"
    local source_root="$2"
    local target_root="$3"

    # Get relative path
    relative_path="${source_file#$source_root/}"
    if [[ "$relative_path" == "$source_file" ]]; then
        relative_path="${source_file#$source_root}"
        relative_path="${relative_path#/}"
    fi

    local target_file="$target_root/$relative_path"
    local target_dir=$(dirname "$target_file")

    mkdir -p "$target_dir" 2>/dev/null || {
        echo "Failed to create directory: $target_dir"
        return 1
    }

    local full_source_path="$source_root/$relative_path"
    if [[ -f "$full_source_path" ]]; then
        cp -f "$full_source_path" "$target_file" && echo "Copied: $relative_path"
    fi
}

# Create an empty placeholder file
function new_placeholder_file {
    local file="$1"
    local target_root="$2"

    # Validate and clean file name
    local clean_file=$(echo "$file" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
    [[ -z "$clean_file" ]] && { echo "Skipping empty file name"; return; }
    clean_file=$(echo "$clean_file" | tr -cd '[:print:]')
    [[ -z "$clean_file" ]] && { echo "Skipping invalid file name"; return; }

    local placeholder_path="$target_root/$clean_file"
    local placeholder_dir=$(dirname "$placeholder_path")

    mkdir -p "$placeholder_dir" 2>/dev/null || {
        echo "Failed to create directory: $placeholder_dir"
        return
    }

    touch "$placeholder_path" && echo "Created placeholder: $clean_file"
}

# Main script execution

echo "Git Changes Collector"
echo "===================="

# Default parameters
output_folder="collected_changes"
repositories=()

# Parse command line options
while [[ $# -gt 0 ]]; do
    case "$1" in
        -o|--output-folder)
            output_folder="$2"
            shift 2
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        *)
            repositories+=("$1")
            shift
            ;;
    esac
done

# Use default repositories if none specified
if [[ ${#repositories[@]} -eq 0 ]]; then
    repositories=("$HOME/workspace/demo" "$HOME/workspace/demo/matrix_index")
fi

# Create target folder in user's workspace
echo "Processing ${#repositories[@]} repositories..."

workspace_path="$HOME/workspace"
target_folder="$workspace_path/$output_folder"

mkdir -p "$target_folder" 2>/dev/null || {
    echo "Failed to create target folder: $target_folder"
    exit 1
}
echo "Created target folder: $target_folder"

# Process each repository
for repo_path in "${repositories[@]}"; do
    # Resolve absolute path
    full_repo_path=$(cd "$repo_path" 2>/dev/null && pwd)
    if [[ -z "$full_repo_path" ]]; then
        echo "Warning: Repository path does not exist: $repo_path"
        continue
    fi

    if [[ ! -d "$full_repo_path" ]]; then
        echo "Warning: Repository path is not a directory: $full_repo_path"
        continue
    fi

    if ! test_git_repository "$full_repo_path"; then
        echo "Warning: Path '$full_repo_path' is not a valid Git repository"
        continue
    fi

    echo "Processing repository: $full_repo_path"
    repo_name=$(basename "$full_repo_path")
    echo "Repository name: $repo_name"

    # Create repository-specific folder
    repo_target_folder="$target_folder/$repo_name"
    mkdir -p "$repo_target_folder" 2>/dev/null || {
        echo "Failed to create repository folder: $repo_target_folder"
        continue
    }

    # Get changed files
    echo "Getting changed files..."
    changed_files=$(get_changed_files "$full_repo_path")
    file_count=$(echo "$changed_files" | wc -l | tr -d '[:space:]')

    if [[ $file_count -eq 0 ]]; then
        echo "No changed files in repository '$repo_name'"
        continue
    fi

    echo "Found $file_count changed files"

    # Copy changed files
    for file in $changed_files; do
        if [[ -n "$file" ]]; then
            copy_file_with_structure "$file" "$full_repo_path" "$repo_target_folder"
        fi
    done

    # Process deleted files
    deleted_files=$(get_deleted_files "$full_repo_path")
    if [[ -n "$deleted_files" ]]; then
        echo "Processing deleted file placeholders..."
        for dfile in $deleted_files; do
            if [[ -n "$dfile" ]]; then
                new_placeholder_file "$dfile" "$repo_target_folder"
            fi
        done
    fi

    echo "[OK] Repository '$repo_name' processed"
done

echo ""
echo "Task completed!"
echo "Changed files saved to: $target_folder"
echo "Folder name: $output_folder"